home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / sbin / update-rc.d < prev    next >
Text File  |  2008-10-14  |  8KB  |  292 lines

  1. #! /usr/bin/perl
  2. #
  3. # update-rc.d    Update the links in /etc/rc[0-9S].d/
  4. #
  5.  
  6. use strict;
  7. use warnings;
  8.  
  9. my $initd = "/etc/init.d";
  10. my $etcd  = "/etc/rc";
  11. my $notreally = 0;
  12.  
  13. # Only parse the LSB headers when this flag exist.  It is to be used
  14. # while we test this new feature, and should be removed when we are
  15. # confident that LSB headers are correct. [pere 2006-09-06]
  16. my $lsbparseflag = "/etc/update-rc.d-lsbparse";
  17.  
  18. # Print usage message and die.
  19.  
  20. sub usage {
  21.     print STDERR "update-rc.d: error: @_\n" if ($#_ >= 0);
  22.     print STDERR <<EOF;
  23. usage: update-rc.d [-n] [-f] <basename> remove
  24.        update-rc.d [-n] <basename> defaults [NN | SS KK]
  25.        update-rc.d [-n] <basename> start|stop NN runlvl [runlvl] [...] .
  26.         -n: not really
  27.         -f: force
  28. EOF
  29.     exit (1);
  30. }
  31.  
  32. # Check out options.
  33. my $force;
  34.  
  35. while($#ARGV >= 0 && ($_ = $ARGV[0]) =~ /^-/) {
  36.     shift @ARGV;
  37.     if (/^-n$/) { $notreally++; next }
  38.     if (/^-f$/) { $force++; next }
  39.     if (/^-h|--help$/) { &usage; }
  40.     &usage("unknown option");
  41. }
  42.  
  43. # Action.
  44.  
  45. &usage() if ($#ARGV < 1);
  46. my $bn = shift @ARGV;
  47.  
  48. unless ($bn =~ m/[a-zA-Z0-9+.-]+/) {
  49.     print STDERR "update-rc.d: illegal character in name '$bn'\n";
  50.     exit (1);
  51. }
  52.  
  53. if ($ARGV[0] ne 'remove') {
  54.     if (! -f "$initd/$bn") {
  55.     print STDERR "update-rc.d: $initd/$bn: file does not exist\n";
  56.     exit (1);
  57.     }
  58. } elsif (-f "$initd/$bn") {
  59.     if (!$force) {
  60.     printf STDERR "update-rc.d: $initd/$bn exists during rc.d purge (use -f to force)\n";
  61.     exit (1);
  62.     }
  63. }
  64.  
  65. my @startlinks;
  66. my @stoplinks;
  67.  
  68. $_ = $ARGV[0];
  69. if    (/^remove$/)       { &checklinks ("remove"); }
  70. elsif (/^defaults$/)     { &defaults; &makelinks }
  71. elsif (/^multiuser$/)    { &multiuser; &makelinks }
  72. elsif (/^(start|stop)$/) { &startstop; &makelinks; }
  73. else                     { &usage; }
  74.  
  75. exit (0);
  76.  
  77. # Check if there are links in /etc/rc[0-9S].d/ 
  78. # Remove if the first argument is "remove" and the links 
  79. # point to $bn.
  80.  
  81. sub is_link () {
  82.     my ($op, $fn, $bn) = @_;
  83.     if (! -l $fn) {
  84.     print STDERR "update-rc.d: warning: $fn is not a symbolic link\n";
  85.     return 0;
  86.     } else {
  87.     my $linkdst = readlink ($fn);
  88.     if (! defined $linkdst) {
  89.         die ("update-rc.d: error reading symbolic link: $!\n");
  90.     }
  91.     if (($linkdst ne "../init.d/$bn") && ($linkdst ne "$initd/$bn")) {
  92.         print STDERR "update-rc.d: warning: $fn is not a link to ../init.d/$bn or $initd/$bn\n";
  93.         return 0;
  94.     }
  95.     }
  96.     return 1;
  97. }
  98.  
  99. sub checklinks {
  100.     my ($i, $found, $fn, $islnk);
  101.  
  102.     print " Removing any system startup links for $initd/$bn ...\n"
  103.     if (defined $_[0] && $_[0] eq 'remove');
  104.  
  105.     $found = 0;
  106.  
  107.     foreach $i (0..9, 'S') {
  108.     unless (chdir ("$etcd$i.d")) {
  109.         next if ($i =~ m/^[789S]$/);
  110.         die("update-rc.d: chdir $etcd$i.d: $!\n");
  111.     }
  112.     opendir(DIR, ".");
  113.     my $saveBN=$bn;
  114.     $saveBN =~ s/\+/\\+/g;
  115.     foreach $_ (readdir(DIR)) {
  116.         next unless (/^[SK]\d\d$saveBN$/);
  117.         $fn = "$etcd$i.d/$_";
  118.         $found = 1;
  119.         $islnk = &is_link ($_[0], $fn, $bn);
  120.         next unless (defined $_[0] and $_[0] eq 'remove');
  121.         if (! $islnk) {
  122.         print "   $fn is not a link to ../init.d/$bn; not removing\n"; 
  123.         next;
  124.         }
  125.         print "   $etcd$i.d/$_\n";
  126.         next if ($notreally);
  127.         unlink ("$etcd$i.d/$_") ||
  128.         die("update-rc.d: unlink: $!\n");
  129.     }
  130.     closedir(DIR);
  131.     }
  132.     $found;
  133. }
  134.  
  135. sub parse_lsb_header {
  136.     my $initdscript = shift;
  137.     my %lsbinfo;
  138.     my $lsbheaders = "Provides|Required-Start|Required-Stop|Default-Start|Default-Stop";
  139.     open(INIT, "<$initdscript") || die "error: unable to read $initdscript";
  140.     while (<INIT>) {
  141.         chomp;
  142.         $lsbinfo{'found'} = 1 if (m/^\#\#\# BEGIN INIT INFO$/);
  143.         last if (m/\#\#\# END INIT INFO$/);
  144.         if (m/^\# ($lsbheaders):\s*(\S?.*)$/i) {
  145.         $lsbinfo{lc($1)} = $2;
  146.         }
  147.     }
  148.     close(INIT);
  149.  
  150.     # Check that all the required headers are present
  151.     if (!$lsbinfo{found}) {
  152.     printf STDERR "update-rc.d: warning: $initdscript missing LSB style header\n";
  153.     } else {
  154.         for my $key (split(/\|/, lc($lsbheaders))) {
  155.             if (!exists $lsbinfo{$key}) {
  156.                 print STDERR "update-rc.d: warning: $initdscript missing LSB style header entry '$key'\n";
  157.             }
  158.         }
  159.     }
  160.     return %lsbinfo;
  161. }
  162.  
  163.  
  164. # Process the arguments after the "defaults" keyword.
  165.  
  166. sub defaults {
  167.     my ($start, $stop) = (20, 20);
  168.  
  169.     &usage ("defaults takes only one or two codenumbers") if ($#ARGV > 2);
  170.     $start = $stop = $ARGV[1] if ($#ARGV >= 1);
  171.     $stop  =         $ARGV[2] if ($#ARGV >= 2);
  172.     &usage ("codenumber must be a number between 0 and 99")
  173.     if ($start !~ /^\d\d?$/ || $stop  !~ /^\d\d?$/);
  174.  
  175.     $start = sprintf("%02d", $start);
  176.     $stop  = sprintf("%02d", $stop);
  177.  
  178.     my %lsbinfo = parse_lsb_header("$initd/$bn");
  179.     if (-e $lsbparseflag && exists $lsbinfo{'default-stop'}) {
  180.     for my $level (split(/\s+/, $lsbinfo{'default-stop'})) {
  181.         $level = 99 if ($level eq 'S');
  182.         $stoplinks[$level] = "K$stop";
  183.     }
  184.     } else {
  185.     $stoplinks[0] = $stoplinks[1] = $stoplinks[6] = "K$stop";
  186.     }
  187.  
  188.     if (exists $lsbinfo{'default-start'}) {
  189.     for my $level (split(/\s+/, $lsbinfo{'default-start'})) {
  190.         $level = 99 if ($level eq 'S');
  191.         $startlinks[$level] = "S$start";
  192.     }
  193.     } else {
  194.     $startlinks[2] = $startlinks[3] =
  195.         $startlinks[4] = $startlinks[5] = "S$start";
  196.     }
  197.  
  198.     1;
  199. }
  200.  
  201. # Process the arguments after the "multiuser" keyword.
  202.  
  203. sub multiuser {
  204.     my ($start, $stop) = (20, 20);
  205.  
  206.     print STDERR "update-rc.d: warning: multiuser is deprecated; specify runlevels manually\n";
  207.     &usage ("multiuser takes only one or two codenumbers") if ($#ARGV > 2);
  208.     $start = $stop = $ARGV[1] if ($#ARGV >= 1);
  209.     $stop  =         $ARGV[2] if ($#ARGV >= 2);
  210.     &usage ("codenumber must be a number between 0 and 99")
  211.     if ($start !~ /^\d\d?$/ || $stop  !~ /^\d\d?$/);
  212.  
  213.     $start = sprintf("%02d", $start);
  214.     $stop  = sprintf("%02d", $stop);
  215.  
  216.     $stoplinks[1] = "K$stop";
  217.     $startlinks[2] = $startlinks[3] =
  218.     $startlinks[4] = $startlinks[5] = "S$start";
  219.  
  220.     1;
  221. }
  222.  
  223. # Process the arguments after the start or stop keyword.
  224.  
  225. sub startstop {
  226.  
  227.     my($letter, $NN, $level);
  228.  
  229.     while ($#ARGV >= 0) {
  230.     if    ($ARGV[0] eq 'start') { $letter = 'S'; }
  231.     elsif ($ARGV[0] eq 'stop')  { $letter = 'K' }
  232.     else {
  233.         &usage("expected start|stop");
  234.     }
  235.  
  236.     if ($ARGV[1] !~ /^\d\d?$/) {
  237.         &usage("expected NN after $ARGV[0]");
  238.     }
  239.     $NN = sprintf("%02d", $ARGV[1]);
  240.  
  241.     shift @ARGV; shift @ARGV;
  242.     $level = shift @ARGV;
  243.     do {
  244.         if ($level !~ m/^[0-9S]$/) {
  245.         &usage(
  246.                "expected runlevel [0-9S] (did you forget \".\" ?)");
  247.         }
  248.         if (! -d "$etcd$level.d") {
  249.         print STDERR
  250.             "update-rc.d: $etcd$level.d: no such directory\n";
  251.         exit(1);
  252.         }
  253.         $level = 99 if ($level eq 'S');
  254.         $startlinks[$level] = "$letter$NN" if ($letter eq 'S');
  255.         $stoplinks[$level]  = "$letter$NN" if ($letter eq 'K');
  256.     } while (($level = shift @ARGV) ne '.');
  257.     &usage("action with list of runlevels not terminated by \`.'")
  258.         if ($level ne '.');
  259.     }
  260.     1;
  261. }
  262.  
  263. # Create the links.
  264.  
  265. sub makelinks {
  266.     my($t, $i);
  267.     my @links;
  268.  
  269.     if (&checklinks) {
  270.     print " System startup links for $initd/$bn already exist.\n";
  271.     exit (0);
  272.     }
  273.     print " Adding system startup for $initd/$bn ...\n";
  274.  
  275.     # nice unreadable perl mess :)
  276.  
  277.     for($t = 0; $t < 2; $t++) {
  278.     @links = $t ? @startlinks : @stoplinks;
  279.     for($i = 0; $i <= $#links; $i++) {
  280.         my $lvl = $i;
  281.         $lvl = 'S' if ($i == 99);
  282.         next if (!defined $links[$i] or $links[$i] eq '');
  283.         print "   $etcd$lvl.d/$links[$i]$bn -> ../init.d/$bn\n";
  284.         next if ($notreally);
  285.         symlink("../init.d/$bn", "$etcd$lvl.d/$links[$i]$bn")
  286.         || die("update-rc.d: symlink: $!\n");
  287.     }
  288.     }
  289.  
  290.     1;
  291. }
  292.